package com.yunji.aggregate.service;

import com.alibaba.fastjson2.util.DateUtils;
import com.yunji.aggregate.cache.AggregateCache;
import com.yunji.aggregate.convert.AggregateParamConvert;
import com.yunji.aggregate.convert.StatisticsDataConvert;
import com.yunji.aggregate.mapper.IAnalysisComplexMapper;
import com.yunji.aggregate.mapper.IAnalysisSimpleMapper;
import com.yunji.aggregate.model.dto.analysis.*;
import com.yunji.aggregate.model.dto.base.AllianceCountParam;
import com.yunji.aggregate.model.dto.base.AuditCountParam;
import com.yunji.aggregate.model.dto.base.ProductAgentCountParam;
import com.yunji.aggregate.model.dto.container.CabinetCountDTO;
import com.yunji.aggregate.model.dto.container.FillCargoCountParam;
import com.yunji.aggregate.model.dto.container.FillCargoParam;
import com.yunji.aggregate.model.dto.stock.StatisticsDataParam;
import com.yunji.aggregate.model.vo.analysis.*;
import com.yunji.aggregate.model.vo.container.CabinetCellVO;
import com.yunji.aggregate.model.vo.container.FillCargoContainerVO;
import com.yunji.aggregate.model.vo.container.FillCargoProductVO;
import com.yunji.common.base.BaseBusiness;
import com.yunji.common.constant.LogicCode;
import com.yunji.common.enums.business.*;
import com.yunji.common.enums.common.ErrorEnum;
import com.yunji.common.enums.common.UserType;
import com.yunji.common.model.domain.StaffDO;
import com.yunji.common.model.dto.LoginInfo;
import com.yunji.common.utils.DecimalUtils;
import com.yunji.common.utils.TimeUtils;
import com.yunji.common.utils.bean.BeanUtils;
import com.yunji.system.context.SystemContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @Project: yunji-coffee
 * @Package com.yunji.user.business
 * @FileName AnalysisBusiness.java
 * @Copyright Copyright © 2024 云集互联. All Rights Reserved
 * Company		com
 * @CreateTime 2024-06-04 14:33:38
 * @Description 交易数据
 * @Modification Author                    History Time			Version				Description
 * --------------------------------------------------------------------------------
 * HuaAo0803@163.com	2024-06-04 14:33:38		1.0					1.0 Version
 * @since JDK 1.8.0_202
 */
@Component
public class AnalysisService extends BaseBusiness {

    @Resource
    private IAnalysisComplexMapper complexMapper;

    @Resource
    private IAnalysisSimpleMapper simpleMapper;


    private static final String BEGIN_DAY = "beginDay";

    private static final String CLOSE_DAY = "closeDay";

    // 首页商品销售条数限制
    private static final Integer ITEM_LIMIT = 14;

    // 首页商品销售多余数据统一名称
    private static final String OTHER = "其他";

    // 销售统计列表
    private static final String SALE_LIST = "saleList";

    // 收益统计列表
    private static final String EARN_LIST = "earnList";


    /*-------------------------------------------------管理端--------------------------------------------------------*/

    /**
     * @Title todayData
     * @Desc 获取当日数据
     * @Date 2024-09-02 17:05:53.506
     * @Return HomeCurrentData 订单数据
     */
    public HomeCurrentVO todayData() {
        HomeDataParam param = new HomeDataParam();
        param.setBelongId(SystemContext.getBelongId());
        // 今日销售总额
        BigDecimal orderAmount = simpleMapper.countOrderAmount(param);
        // 今日销售笔数
        Integer orderNums = simpleMapper.countOrderNums(param);
        // 今日销售收益
        BigDecimal orderEarns = simpleMapper.countOrderEarns(param);
        // 今日售后笔数
        Integer orderRefund = simpleMapper.countOrderRefund(param);
        HomeCurrentVO data = new HomeCurrentVO();
        data.setOrderAmount(orderAmount);
        data.setOrderNums(orderNums);
        data.setOrderEarns(orderEarns);
        data.setOrderRefund(orderRefund);
        return data;
    }

    /**
     * @Title saleTrend
     * @Desc 销售走势图
     * @Date 2024-09-03 14:25:53.865
     * @Return Object
     */
    public List<SaleTrendVO> saleTrend(Integer trendType) {
        LoginInfo user = SystemContext.getUser();
        String userType = user.getUserType();
        Long belongId = user.getBelongId();
        logs.info("【销售走势图】当前登录用户类型:{},当前用户所属ID:{}", userType, belongId);
        Map<String, LocalDate> timeMap = handleTime(trendType);
        LocalDate beginDay = timeMap.get(BEGIN_DAY);
        LocalDate closeDay = timeMap.get(CLOSE_DAY);
        LocalDateTime min = TimeUtils.getMinDay(beginDay);
        LocalDateTime max = TimeUtils.getMaxDay(closeDay);
        HomeDataParam param = new HomeDataParam();
        param.setTrendType(trendType);
        List<SaleTrendVO> list;
        List<SaleTrendVO> trendList;
        if (Objects.equals(UserType.PLATE.getCode(), userType) && !Objects.equals(TrendType.RECENT_YEAR.getCode(), trendType)) {
            list = simpleMapper.countAdminTrendOfDay(min, max);
        } else if (Objects.equals(UserType.PLATE.getCode(), userType) && Objects.equals(TrendType.RECENT_YEAR.getCode(), trendType)) {
            list = simpleMapper.countAdminTrendOfMonth(min, max);
        } else if (Objects.equals(TrendType.RECENT_YEAR.getCode(), trendType)) {
            list = simpleMapper.countSaleTrendOfMonth(param, min, max);
        } else {
            list = simpleMapper.countSaleTrendOfDay(param, min, max);
        }
        StatsDTO dto = new StatsDTO();
        dto.setBeginDay(beginDay);
        dto.setCloseDay(closeDay);
        dto.set(SALE_LIST, list);
        if (Objects.equals(TrendType.RECENT_YEAR.getCode(), trendType)) {
            dto.setStatsType(StatsType.MONTH.getCode());
            trendList = convertSaleTrend(dto);
        } else {
            dto.setStatsType(StatsType.DAY.getCode());
            trendList = convertSaleTrend(dto);
        }
        return trendList;
    }


    /**
     * @param trendType 趋势类型
     * @Title earnTrend
     * @Desc 收益趋势图
     * @Date 2024-09-03 16:56:44.117
     * @Return List<EarnTrend>
     */
    public Map<String, List<EarnTrendVO>> earnTrend(Integer trendType) {
        Map<String, List<EarnTrendVO>> map = new HashMap<>();

        LoginInfo user = SystemContext.getUser();
        String userType = user.getUserType();
        Long belongId = user.getBelongId();
        logs.info("【收益趋势图】当前登录用户类型:{},当前用户所属ID:{}", userType, belongId);

        Map<String, LocalDate> timeMap = handleTime(trendType);
        LocalDate beginDay = timeMap.get(BEGIN_DAY);
        LocalDate closeDay = timeMap.get(CLOSE_DAY);
        LocalDateTime min = TimeUtils.getMinDay(beginDay);
        LocalDateTime max = TimeUtils.getMaxDay(closeDay);

        HomeDataParam siteParam = new HomeDataParam();
        siteParam.setEarnType(TradeTypes.SITE_SCALE.getCode());
        if (Objects.equals(UserType.SITE.getCode(), userType)) {
            siteParam.setBelongId(belongId);
        }
        siteParam.setTrendType(trendType);

        HomeDataParam agentParam = new HomeDataParam();
        agentParam.setEarnType(TradeTypes.AGENT_SCALE.getCode());
        if (Objects.equals(UserType.AGENT.getCode(), userType)) {
            agentParam.setParentId(belongId);
        }
        agentParam.setTrendType(trendType);

        HomeDataParam adminParam = new HomeDataParam();
        adminParam.setEarnType(TradeTypes.PLATE.getCode());
        adminParam.setTrendType(trendType);

        List<EarnTrendVO> adminList;
        List<EarnTrendVO> agentList;
        List<EarnTrendVO> siteList;

        List<EarnTrendVO> siteResponse;
        List<EarnTrendVO> agentResponse;
        List<EarnTrendVO> adminResponse;

        StatsDTO dto = new StatsDTO();
        dto.setCloseDay(closeDay);
        dto.setBeginDay(beginDay);
        if (Objects.equals(TrendType.RECENT_YEAR.getCode(), trendType)) {
            siteList = complexMapper.countOrderEarnsOfMonth(siteParam, TradeTypes.SITE_SCALE.getCode(), min, max);
            agentList = complexMapper.countOrderEarnsOfMonth(agentParam, TradeTypes.AGENT_SCALE.getCode(), min, max);
            adminList = complexMapper.countOrderEarnsOfMonth(adminParam, TradeTypes.PLATE.getCode(), min, max);

            dto.setStatsType(StatsType.MONTH.getCode());
            dto.set(EARN_LIST, siteList);
            siteResponse = addEarnTrend(dto);
            dto.set(EARN_LIST, agentList);
            agentResponse = addEarnTrend(dto);
            dto.set(EARN_LIST, adminList);
            adminResponse = addEarnTrend(dto);

        } else {
            siteList = complexMapper.countOrderEarnsOfDay(siteParam, TradeTypes.SITE_SCALE.getCode(), min, max);
            agentList = complexMapper.countOrderEarnsOfDay(agentParam, TradeTypes.AGENT_SCALE.getCode(), min, max);
            adminList = complexMapper.countOrderEarnsOfDay(adminParam, TradeTypes.PLATE.getCode(), min, max);

            dto.setStatsType(StatsType.DAY.getCode());
            dto.set(EARN_LIST, siteList);
            siteResponse = addEarnTrend(dto);
            dto.set(EARN_LIST, agentList);
            agentResponse = addEarnTrend(dto);
            dto.set(EARN_LIST, adminList);
            adminResponse = addEarnTrend(dto);
        }

        if (Objects.equals(UserType.SITE.getCode(), userType)) {
            map.put(UserType.SITE.getCode(), siteResponse);
        } else if (Objects.equals(UserType.AGENT.getCode(), userType)) {
            map.put(UserType.AGENT.getCode(), agentResponse);
        } else {
            map.put(UserType.SITE.getCode(), siteResponse);
            map.put(UserType.AGENT.getCode(), agentResponse);
            map.put(UserType.PLATE.getCode(), adminResponse);
        }

        return map;
    }

    /**
     * @param trendType 趋势类型
     * @Title amountRatio
     * @Desc 商品销售额占比
     * @Date 2024-09-04 14:28:13.729
     * @Return List<ProductRatio>
     */
    public List<ProductRatioVO> amountRatio(Integer trendType, Integer ratioType) {

        Map<String, LocalDate> timeMap = handleTime(trendType);
        LocalDate beginDay = timeMap.get(BEGIN_DAY);
        LocalDate closeDay = timeMap.get(CLOSE_DAY);
        LocalDateTime min = TimeUtils.getMinDay(beginDay);
        LocalDateTime max = TimeUtils.getMaxDay(closeDay);

        HomeDataParam param = new HomeDataParam();
        param.setBelongId(SystemContext.getBelongId());
        List<ProductRatioVO> ratioList = simpleMapper.salesOfProducts(param, min, max);
        if (BeanUtils.isNotNull(ratioList) && ratioList.size() > ITEM_LIMIT) {
            ProductRatioVO other = new ProductRatioVO();
            BigDecimal otherAmount = BigDecimal.ZERO;
            int otherCount = 0;
            for (int i = ITEM_LIMIT; i < ratioList.size() - 1; i++) {
                otherAmount = otherAmount.add(ratioList.get(i).getProductAmount());
                otherCount = otherCount + ratioList.get(i).getProductCount();
            }
            other.setProductAmount(otherAmount);
            other.setProductCount(otherCount);
            other.setProductName(OTHER);
            ratioList = ratioList.stream().limit(ITEM_LIMIT).collect(Collectors.toList());
            ratioList.add(other);
        }

        return ratioList;
    }

    /**
     * @Title awaitHandle
     * @Desc 待处理事项
     * @Date 2024-09-06 09:24:23.043
     * @Return AwaitHandleData
     */
    public AwaitHandleVO awaitHandle() {
        LoginInfo user = SystemContext.getUser();
        String userType = user.getUserType();
        Long belongId = user.getBelongId();
        logs.info("【待处理事项】当前登录用户类型:{},当前用户所属ID:{}", userType, belongId);

        // 统计售后待审核
        RefundCountParam refundParam = new RefundCountParam();
        refundParam.setApplyStatus(0);
        Integer refundNums = simpleMapper.countRefund(refundParam);
        // 统计提现待审核
        PayoutCountParam payoutParam = new PayoutCountParam();
        // 自营网点待审核
        AuditCountParam siteParam = new AuditCountParam();
        // 统计坏返待审核
        AuditCountParam repairParam = new AuditCountParam();
        // 统计报废待审核
        AuditCountParam discardParam = new AuditCountParam();
        // 统计盘点待审核
        AuditCountParam stockTakeParam = new AuditCountParam();
        // 统计待入库单
        StorageTicketCountParam storageTicketParam = new StorageTicketCountParam();
        // 统计待上传物流信息
        StorageTicketCountParam outStorageParam = new StorageTicketCountParam();
        if (!Objects.equals(UserType.PLATE.getCode(), userType)) {
            payoutParam.setBelongId(belongId);
            siteParam.setBelongId(belongId);
            repairParam.setBelongId(belongId);
            discardParam.setBelongId(belongId);
            stockTakeParam.setBelongId(belongId);
        }
        storageTicketParam.setBelongId(belongId);
        outStorageParam.setBelongId(belongId);
        payoutParam.setApplyStatus(1);
        Integer payoutNums = simpleMapper.countPayout(payoutParam);

        siteParam.setAuditStatus(AuditStatus.WAIT.getCode());
        Integer siteNums = simpleMapper.countSiteAudit(siteParam);

        // 统计加盟待审核
        AllianceCountParam allianceParam = new AllianceCountParam();
        allianceParam.setAllianceStatus(AuditStatus.WAIT.getCode());
        Integer allianceNums = simpleMapper.countAlliance(allianceParam);

        repairParam.setAuditStatus(AuditStatus.WAIT.getCode());
        Integer repairNums = simpleMapper.countRepair(repairParam);

        discardParam.setAuditStatus(AuditStatus.WAIT.getCode());
        Integer discardNums = simpleMapper.countDiscard(discardParam);

        stockTakeParam.setAuditStatus(AuditStatus.WAIT.getCode());
        Integer stockTakeNums = simpleMapper.countStockTake(stockTakeParam);

        storageTicketParam.setStorageStatus(StorageStatus.WAIT_STORAGE.getCode());
        storageTicketParam.setStorageType(StorageType.INTO_STORAGE.getCode());
        Integer intoNums = simpleMapper.countStorageTicket(storageTicketParam);

        outStorageParam.setOperateStatus(StorageOperateSatus.NONE.getCode());
        outStorageParam.setStorageStatus(StorageStatus.ALREADY_STORAGE.getCode());
        outStorageParam.setStorageType(StorageType.OUT_STORAGE.getCode());
        Integer outNums = simpleMapper.countStorageTicket(outStorageParam);

        AwaitHandleVO awaitHandleData = new AwaitHandleVO();
        Map<Integer, Integer> map = new HashMap<>();
        if (Objects.equals(UserType.PLATE.getCode(), userType)) {
            map.put(AuditTypes.REFUND.getCode(), refundNums);
            map.put(AuditTypes.ALLIANCE.getCode(), allianceNums);
        }
        map.put(AuditTypes.PAYOUT.getCode(), payoutNums);
        map.put(AuditTypes.SITE.getCode(), siteNums);
        map.put(AuditTypes.REPAIR.getCode(), repairNums);
        map.put(AuditTypes.DISCARD.getCode(), discardNums);
        map.put(AuditTypes.STOCK_TAKE.getCode(), stockTakeNums);
        awaitHandleData.setAuditMap(map);
        awaitHandleData.setIntoStorage(intoNums);
        awaitHandleData.setExpressStorage(outNums);
        return awaitHandleData;
    }

    /**
     * @Title productInfo
     * @Desc 商品概况
     * @Date 2024-09-06 15:02:22.791
     * @Return ProductInfoData
     */
    public ProductInfoVO productInfo() {
        LoginInfo user = SystemContext.getUser();
        String userType = user.getUserType();
        Long belongId = user.getBelongId();
        logs.info("【商品概况】当前登录用户类型:{},当前用户所属ID:{}", userType, belongId);

        // 统计全部商品
        Integer productNums = simpleMapper.countProduct(ProductAgentCountParam.builder().belongId(belongId).status(LogicCode.NO).build());

        // 可用库存
        BigDecimal usableStock = simpleMapper.allUsableStock(belongId);

        // 达到预警值的库存
        Integer lowStock = simpleMapper.warnStock(belongId);

        ProductInfoVO productInfoData = new ProductInfoVO();
        productInfoData.setProductNums(productNums);
        productInfoData.setUsableStock(usableStock);
        productInfoData.setLowStock(lowStock);
        return productInfoData;
    }


    /**
     * @param param 过滤信息
     * @Title salesStats
     * @Desc 销售统计
     * @Date 2024-09-12 15:00:59.004
     * @Return List<SaleTrend>
     */
    public List<SaleTrendVO> salesStats(StatisticsDataParam param) {
        Integer statsType = param.getStatsType();
        StatisticsDataConvert.paramTime(param);
        LocalDate begin = DateUtils.parseLocalDate(param.getBeginDay());
        LocalDate close = DateUtils.parseLocalDate(param.getCloseDay());
        List<SaleTrendVO> trendList;
        // 返回简短的日期
        param.setShortStr(true);
        List<SaleTrendVO> list = complexMapper.salesStats(param);
        StatsDTO statsDTO = new StatsDTO();
        statsDTO.setBeginDay(begin);
        statsDTO.setCloseDay(close);
        statsDTO.setStatsType(statsType);
        statsDTO.set(SALE_LIST, list);
        trendList = convertSaleTrend(statsDTO);
        return trendList;
    }

    /**
     * @param param 过滤信息
     * @Title earnsStats
     * @Desc 收益统计
     * @Date 2024-09-12 15:27:41.328
     * @Return List<PlatformEarnData>
     */
    public List<PlatformEarnVO> earnsStats(StatisticsDataParam param) {
        LoginInfo user = SystemContext.getUser();
        String userType = user.getUserType();
        Long belongId = user.getBelongId();
        logs.info("【收益统计】当前登录用户类型:{},当前用户所属ID:{}", userType, belongId);
        if (Objects.equals(UserType.PLATE.getCode(), userType)) {
            param.setTradeType(TradeTypes.PLATE.getCode());
        }
        if (Objects.equals(UserType.AGENT.getCode(), userType)) {
            param.setParentId(belongId);
            param.setTradeType(TradeTypes.AGENT_SCALE.getCode());
        }
        if (Objects.equals(UserType.SITE.getCode(), userType)) {
            param.setBelongId(belongId);
            param.setTradeType(TradeTypes.SITE_SCALE.getCode());
        }
        Integer statsType = param.getStatsType();
        logs.info("【收益统计】统计类型:{}", statsType);
        Assert.isTrue(BeanUtils.isNotNull(statsType), ErrorEnum.CHECKED_911001.getText());
        StatisticsDataConvert.paramTime(param);
        LocalDate begin = DateUtils.parseLocalDate(param.getBeginDay());
        LocalDate close = DateUtils.parseLocalDate(param.getCloseDay());
        StatsDTO dto = new StatsDTO();
        dto.setStatsType(param.getStatsType());
        dto.setBeginDay(begin);
        dto.setCloseDay(close);
        param.setShortStr(true);
        List<EarnTrendVO> list = complexMapper.earnsStatsByDay(param);
        dto.set(EARN_LIST, list);
        List<EarnTrendVO> trendList = addEarnTrend(dto);
        List<PlatformEarnVO> dateList = new ArrayList<>();
        // 处理收益比例
        for (EarnTrendVO trendData : trendList) {
            PlatformEarnVO data = new PlatformEarnVO();
            BeanUtils.clone(trendData, data);
            BigDecimal orderAmount = trendData.getOrderAmount();
            BigDecimal earnAmount = trendData.getEarnAmount();
            if (!DecimalUtils.compare(orderAmount, BigDecimal.ZERO) && !DecimalUtils.compare(earnAmount, BigDecimal.ZERO)) {
                BigDecimal ratio = trendData.getEarnAmount().divide(trendData.getOrderAmount(), RoundingMode.CEILING);
                data.setRatio(ratio);
            }
            dateList.add(data);
        }
        return dateList;
    }


    /**
     * @param param 过滤信息
     * @Title agentLinkageQuery
     * @Desc 代理联动查询
     * @Date 2024-09-11 10:47:16.842
     * @Return List<LinkageQueryVO>
     */
    public List<LinkageQueryVO> agentLinkageQuery(LinkageQueryParam param) {
        return simpleMapper.agentLinkageQuery(param);
    }

    /**
     * @param param 过滤信息
     * @Title siteLinkageQuery
     * @Desc 网点联动查询
     * @Date 2024-09-11 11:02:00.621
     * @Return List<LinkageQueryVO>
     */
    public List<LinkageQueryVO> siteLinkageQuery(LinkageQueryParam param) {
        handleLinkageQuery(param);
        return simpleMapper.siteLinkageQuery(param);
    }

    //------------------------------------------------小程序端-------------------------------------------------------

    /**
     * @param cabinetParam 货柜参数
     * @Title fillCargoContainerList
     * @Desc 分页查询货柜补货列表
     * @Date 2024-08-31 10:46:26.036
     * @Return List<FillCargoContainerVO> 货柜补货列表
     */
    public List<FillCargoContainerVO> fillCargoContainerList(FillCargoParam cabinetParam) {
        cabinetParam.setBelongId(SystemContext.getBelongId());
        List<FillCargoContainerVO> list = complexMapper.fillCargoContainerList(cabinetParam);
        List<Long> containerIds = complexMapper.getContainerIds(SystemContext.getBelongId());
        Map<Long, List<CabinetCellVO>> map = containerIds.stream().collect(Collectors.toMap(a -> a, b -> new ArrayList()));
        if (containerIds != null && containerIds.size() > 0) {
            List<CabinetCellVO> cellList = complexMapper.getLockCabinetCell(containerIds);
            for (CabinetCellVO cellVO : cellList) {
                cellVO.setProductName(AggregateCache.getProductName(cellVO.getProductId()));
                List<CabinetCellVO> vos = map.get(cellVO.getContainerId());
                vos.add(cellVO);
            }
        }

        for (FillCargoContainerVO vo : list) {
            Long containerId = vo.getContainerId();
            vo.setLocationName(AggregateCache.getLocationName(vo.getLocationId()));
            List<CabinetCellVO> cellVOS = map.get(containerId);
            vo.setVoList(cellVOS);
        }
        return list;
    }

    /**
     * @param cabinetParam 货柜参数
     * @Title fillCargoProductList
     * @Desc 分页查询商品补货列表
     * @Date 2024-08-31 10:47:29.848
     * @Return List<FillCargoProductVO> 商品补货列表
     */
    public List<FillCargoProductVO> fillCargoProductList(FillCargoParam cabinetParam) {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long belongId = user.getBelongId();
        logs.info("【商品补货列表】所属ID:{}", belongId);
        cabinetParam.setBelongId(belongId);
        return complexMapper.fillCargoProductList(cabinetParam);
    }

    /**
     * @param productId 商品ID
     * @Title fillCargoProductInfo
     * @Desc 商品补货详情
     * @Date 2024-08-31 10:47:58.647
     * @Return List<FillCargoContainerVO> 商品补货详情
     */
    public List<FillCargoContainerVO> fillCargoProductInfo(Long productId) {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long belongId = user.getBelongId();
        logs.info("【商品补货详情】所属ID:{}", belongId);

        FillCargoParam fillCargoParam = new FillCargoParam();
        fillCargoParam.setProductId(productId);
        fillCargoParam.setBelongId(belongId);
        return complexMapper.fillCargoContainerList(fillCargoParam);
    }

    /**
     * @Title fillCargoData
     * @Desc 补货数据
     * @Date 2024-08-31 10:48:21.832
     * @Return FillCargoDataVO 补货数据
     */
    public FillCargoDataVO fillCargoData() {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long userId = user.getUserId();
        Long belongId = user.getBelongId();
        logs.info("【商品补货详情】当前用户ID:{}, 所属ID:{}", userId, belongId);

        // 补货点位
        Integer locationNums = simpleMapper.countCargoLocationByBelongId(belongId);
        // 可补商品
        FillCargoParam param = new FillCargoParam();
        param.setBelongId(belongId);
        Integer productNums = complexMapper.fillCargoProductList(param).stream().mapToInt(FillCargoProductVO::getNums).sum();
        // 无货货柜
        param.setCellStatus(0);
        Integer withoutContainerNums = complexMapper.fillCargoContainerList(param).size();
        // 缺货货柜
        param.setCellStatus(2);
        Integer lackContainerNums = complexMapper.fillCargoContainerList(param).size();
        // 可补货柜
        param.setCellStatus(1);
        Integer containerNums = complexMapper.fillCargoContainerList(param).size();
        // 今日已补货
        Integer todayFillCargoNums = simpleMapper.countStaffFillCargoNums(userId, LogicCode.NO);
        // 总共已补货
        Integer totalFillCargoNums = simpleMapper.countStaffFillCargoNums(userId, LogicCode.YES);
        // 今日已补货商品数
        Integer todayProductNums = simpleMapper.countStaffFillCargoProductNums(userId, LogicCode.NO);
        // 总共补货商品数
        Integer totalProductNums = simpleMapper.countStaffFillCargoProductNums(userId, LogicCode.YES);

        FillCargoDataVO vo = new FillCargoDataVO();
        vo.setLocationNums(locationNums);
        vo.setProductNums(productNums);
        vo.setContainerNums(containerNums);
        vo.setWithoutContainerNums(withoutContainerNums);
        vo.setLackContainerNums(lackContainerNums);
        vo.setTodayFillCargoNums(todayFillCargoNums);
        vo.setTotalFillCargoNums(totalFillCargoNums);
        vo.setTodayProductNums(todayProductNums);
        vo.setTotalProductNums(totalProductNums);
        return vo;
    }

    /**
     * @Title fillCargoDataByMonth
     * @Desc 员工每月补货数据
     * @Date 2024-08-31 10:48:43.249
     * @Return Integer 补货数据
     */
    public FillCargoMonthVO fillCargoDataByMonth(FillCargoCountParam param) {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long userId = user.getUserId();
        param.setStaffId(userId);
        return simpleMapper.fillCargoDataByMonth(param);
    }

    /**
     * @Title fillCargoDateByYear
     * @Desc 员工按年分月补货次数
     * @Date 2024-08-31 10:45:20.847
     * @Return List<FillCargoTimeDataVO>
     */
    public List<FillCargoTimeDataVO> fillCargoCountByDate(FillCargoCountParam param) {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long userId = user.getUserId();
        param.setStaffId(userId);
        List<FillCargoTimeDataVO> dataList = new ArrayList<>();
        if (param.getViewType() == 0) {
            dataList = simpleMapper.fillCargoNums(param);
        } else {
            dataList = simpleMapper.FillCargoProductNums(param);
        }
        return dataList;
    }

    //--------------------------------------------- 补参 -----------------------------------------------

    /**
     * --------------------------------------------- 历史统计 ---------------------------------------------
     */

    private StaffDO currentStaff() {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), "未找到当前登录用户信息");
        Long userId = user.getUserId();
        logs.info("【员工统计】用户ID:{}", userId);
        StaffDO staff = AggregateCache.getStaff(userId);
        Assert.isTrue(BeanUtils.isNotNull(staff), "未找到员工信息");
        return staff;
    }

    /**
     * @Title getStaffTransactionData
     * @Desc 获取员工交易数据统计
     * @Date 2024-06-04 13:58:04.337
     * @Return StaffTradeData 员工交易信息
     */
    public StaffTradeVO getStaffTransactionData() {
        StaffDO staff = currentStaff();
        StaffTradeVO staffData = new StaffTradeVO();
        StaffTradeAnalysisParam sp = StaffTradeAnalysisParam.builder().staffId(staff.getId()).build();
        // 获取货柜的总交易笔数
        int count = simpleMapper.selectTotalCount(sp);
        logs.info("货柜总共交易笔数【{}】", count);

        // 获取货柜的总交易额
        BigDecimal totalPrice = simpleMapper.selectTotalPrice(sp);
        logs.info("货柜总交易额【{}】", totalPrice);

        // 获取本周交易金额
        BigDecimal weekPrice = simpleMapper.selectWeekPrice(sp);
        logs.info("本周交易金额【{}】", weekPrice);

        // 获取上周交易金额
        BigDecimal lastWeekPrice = simpleMapper.selectLastWeekPrice(sp);
        logs.info("上周交易金额【{}】", lastWeekPrice);

        // 获取本月交易金额
        BigDecimal monthPrice = simpleMapper.selectMonthPrice(sp);
        logs.info("本月交易金额【{}】", monthPrice);

        // 获取上月交易金额
        BigDecimal lastMonthPrice = simpleMapper.selectLastMonthPrice(sp);
        logs.info("上月交易金额【{}】", lastMonthPrice);

        staffData.setTotalCount(count);
        staffData.setTotalPrice(totalPrice);
        staffData.setWeekPrice(weekPrice);
        staffData.setMonthPrice(monthPrice);
        staffData.setCompareWeekPrice(calculateGrowthRate(lastWeekPrice, weekPrice));
        staffData.setCompareMonthPrice(calculateGrowthRate(lastMonthPrice, monthPrice));

        return staffData;
    }

    /**
     * @Title getStaffContainerData
     * @Desc 获取员工货柜数据统计
     * @Date 2024-06-04 14:47:22.124
     * @Return StaffContainerData
     */
    public StaffContainerVO getStaffContainerData() {
        StaffContainerVO staffData = new StaffContainerVO();
        StaffDO staff = currentStaff();
        //获取货柜总数量
        Long siteId = staff.getManagerId();
        logs.info("【员工统计】网点ID:{}", siteId);
        List<CabinetCountDTO> cabinetList = simpleMapper.getCabinetBySiteId(siteId);

        //获取货柜总数 货柜激活数 货柜未激活数
        countCabinet(staffData, cabinetList);
        return staffData;
    }


    /**
     * @param month 月份
     * @Title getStaffTransactionDataMonth
     * @Desc 获得月度交易数据
     * @Date 2024-06-04 14:47:37.413
     * @Return StaffTradeDataDetail
     */
    public StaffTradeDetailVO getStaffTransactionDataMonth(String month) {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long userId = user.getUserId();
        logs.info("【交易数据】当前用户ID:{}", userId);
        StaffDO staff = AggregateCache.getStaff(userId);
        StaffTradeDetailVO staffData = new StaffTradeDetailVO();

        StaffTradeAnalysisParam p = StaffTradeAnalysisParam.builder().staffId(staff.getId()).month(month).build();

        // 获取月度交易总额
        BigDecimal totalPrice = simpleMapper.selectMonthPriceByMonth(p);
        logs.info("月度交易总额【{}】", totalPrice);

        // 获取月度交易笔数
        Integer totalCount = simpleMapper.selectMonthCountPriceByMonth(p);
        logs.info("月度交易笔数【{}】", totalCount);

        // 获取月度商品交易数据排行
        List<ProductAmtSumVO> productList = simpleMapper.selectMonthProductByMonth(p);
        logs.info("月度商品销售排行【{}】", productList);

        // 获取该月每日的交易数额
        List<StaffTradeEveryDayVO> dayList = simpleMapper.selectDayTradeByMonth(p);
        logs.info("该月每日交易数额【{}】", dayList);

        //获取当前月份第一天

        LocalDate startDate = getMonthFirstDay(month);

        YearMonth yearMonth = YearMonth.parse(month.substring(0, 7));
        LocalDate endDate = yearMonth.atEndOfMonth();

        // 创建每日统计结果的Map，并初始化为0
        Map<LocalDate, BigDecimal> dailyStatistics = new TreeMap<>();
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            dailyStatistics.put(date, BigDecimal.ZERO);
        }
        // 根据查询结果更新每日统计数据
        for (StaffTradeEveryDayVO staffTradeEveryDay : dayList) {
            dailyStatistics.put(LocalDate.parse(staffTradeEveryDay.getDayTime()), staffTradeEveryDay.getAmount());
        }
        Object[] objects = dailyStatistics.entrySet().toArray();

        staffData.setTotalCount(totalCount);
        staffData.setTotalPrice(totalPrice);
        staffData.setProductRanking(productList);
        staffData.setDetails(objects);

        return staffData;
    }

    /**
     * @Title getStaffContainerDataDetail
     * @Desc 获取货柜近几天交易额
     * @Date 2024-06-04 14:48:12.156
     * @Return Map<String, List < StaffTradeEveryDay>>
     */
    public Map<String, List<StaffTradeEveryDayVO>> getStaffContainerDataDetail() {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), "未找到当前登录用户信息");
        Long userId = user.getUserId();
        logs.info("【员工交易】用户ID:{}", userId);
        StaffDO staff = AggregateCache.getStaff(userId);
        Assert.isTrue(BeanUtils.isNotNull(staff), "未找到员工信息");
        //获取货柜ID集合
        List<Long> ids = getContainerIdsByStaffId(userId);
        //获取近7天交易数据
        List<StaffTradeEveryDayVO> sevenDay = new ArrayList<>();
        List<StaffTradeEveryDayVO> fifteenDay = new ArrayList<>();
        if (BeanUtils.isNotNull(ids)) {
            sevenDay = simpleMapper.selectContainerDataDetailByDay(StaffTradeAnalysisParam.builder().staffId(staff.getId()).day(7).build());
            // 获取近15天交易数据
            fifteenDay = simpleMapper.selectContainerDataDetailByDay(StaffTradeAnalysisParam.builder().staffId(staff.getId()).day(15).build());
        }
        //获取返回数据
        Map<String, List<StaffTradeEveryDayVO>> map = new TreeMap<>();

        map.put("seven", addDayData(sevenDay, 6));
        map.put("fifteen", addDayData(fifteenDay, 14));


        return map;
    }

    //-------------------------------------------方法/补参------------------------------------------------*/

    /**
     * @param param 过滤信息
     * @Title handleLinkageQuery
     * @Desc 处理特殊查询参数
     * @Date 2024-09-11 11:43:22.086
     */
    public void handleLinkageQuery(LinkageQueryParam param) {
        AggregateParamConvert.handleLinkageQuery(param);
    }

    /**
     * @param trendType 时间类型
     * @Title handleTime
     * @Desc 处理时间
     * @Date 2024-09-04 11:16:43.730
     * @Return Map<String, LocalDate>
     */
    public Map<String, LocalDate> handleTime(Integer trendType) {
        Map<String, LocalDate> timeMap = new HashMap<>();

        LocalDate beginDay = LocalDate.now();
        LocalDate closeDay = LocalDate.now();

        if (Objects.equals(TrendType.RECENT_SEVEN.getCode(), trendType)) {
            // 近七天
            beginDay = closeDay.plusDays(-6);
        } else if (Objects.equals(TrendType.THIS_MONTH.getCode(), trendType)) {
            // 本月
            beginDay = beginDay.with(TemporalAdjusters.firstDayOfMonth());
        } else if (Objects.equals(TrendType.LAST_MONTH.getCode(), trendType)) {
            // 上月
            beginDay = beginDay.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
            closeDay = closeDay.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
        } else {
            //近半年
            beginDay = beginDay.minusMonths(5).with(TemporalAdjusters.firstDayOfMonth());
        }

        timeMap.put(BEGIN_DAY, beginDay);
        timeMap.put(CLOSE_DAY, closeDay);

        return timeMap;
    }

    /**
     * @param dto 过滤信息
     * @Title addEarnTrend
     * @Desc 补充收益走势数据
     * @Date 2024-09-21 11:36:08.706
     * @Return List<EarnTrendData>
     */
    public List<EarnTrendVO> addEarnTrend(StatsDTO dto) {
        LocalDate beginDay = dto.getBeginDay();
        LocalDate closeDay = dto.getCloseDay();
        Integer statsType = dto.getStatsType();
        List<EarnTrendVO> list = dto.get(EARN_LIST);

        List<EarnTrendVO> trendList = new ArrayList<>();
        if (Objects.equals(StatsType.DAY.getCode(), statsType)) {
            for (LocalDate date = beginDay; !date.isAfter(closeDay); date = date.plusDays(1)) {
                EarnTrendVO trend = new EarnTrendVO();
                trend.setDate(date.format(DateTimeFormatter.ofPattern("MM-dd")));
                trendList.add(trend);
            }
        }
        if (Objects.equals(StatsType.MONTH.getCode(), statsType)) {
            for (LocalDate date = beginDay; !date.isAfter(closeDay); date = date.plusMonths(1)) {
                EarnTrendVO trend = new EarnTrendVO();
                trend.setDate(date.format(DateTimeFormatter.ofPattern("yyyy-MM")));
                trendList.add(trend);
            }
        }

        Map<String, EarnTrendVO> map = new HashMap<>();
        for (EarnTrendVO earnTrendData : list) {
            map.put(earnTrendData.getDate(), earnTrendData);
        }

        for (EarnTrendVO earnTrendData : trendList) {
            if (map.containsKey(earnTrendData.getDate())) {
                EarnTrendVO data = map.get(earnTrendData.getDate());
                BeanUtils.clone(data, earnTrendData);
            }
        }
        return trendList;
    }

    /**
     * @param dto 过滤信息
     * @Title addSaleTrend
     * @Desc 补充销售走势数据
     * @Date 2024-09-21 11:36:42.739
     */
    public List<SaleTrendVO> convertSaleTrend(StatsDTO dto) {
        List<SaleTrendVO> list = dto.get(SALE_LIST);
        LocalDate beginDate = dto.getBeginDay();
        LocalDate closeDate = dto.getCloseDay();
        Integer statsType = dto.getStatsType();

        List<SaleTrendVO> trendList = new ArrayList<>();
        if (Objects.equals(StatsType.MONTH.getCode(), statsType)) {
            for (LocalDate date = beginDate; !date.isAfter(closeDate); date = date.plusMonths(1)) {
                SaleTrendVO trend = new SaleTrendVO();
                trend.setDate(date.format(DateTimeFormatter.ofPattern("yyyy-MM")));
                trend.setCostPrice(BigDecimal.ZERO);
                trend.setGrossPrice(BigDecimal.ZERO);
                trend.setOrderAmount(BigDecimal.ZERO);
                trend.setOrderNums(0);
                trendList.add(trend);
            }
        }

        if (Objects.equals(StatsType.DAY.getCode(), statsType)) {
            for (LocalDate date = beginDate; !date.isAfter(closeDate); date = date.plusDays(1)) {
                SaleTrendVO trend = new SaleTrendVO();
                trend.setDate(date.format(DateTimeFormatter.ofPattern("MM-dd")));
                trend.setCostPrice(BigDecimal.ZERO);
                trend.setGrossPrice(BigDecimal.ZERO);
                trend.setOrderAmount(BigDecimal.ZERO);
                trend.setOrderNums(0);
                trendList.add(trend);
            }
        }

        Map<String, SaleTrendVO> map = new HashMap<>();
        for (SaleTrendVO saleTrend : list) {
            map.put(saleTrend.getDate(), saleTrend);
        }

        // 根据查询结果更新每日统计数据
        for (SaleTrendVO saleTrend : trendList) {
            if (map.containsKey(saleTrend.getDate())) {
                SaleTrendVO trend = map.get(saleTrend.getDate());
                BeanUtils.clone(trend, saleTrend);
                // 管理员才需要计算毛利
                if (BeanUtils.isNotNull(trend.getCostPrice())) {
                    BigDecimal grossPrice = trend.getOrderAmount().subtract(trend.getCostPrice());
                    saleTrend.setGrossPrice(grossPrice);
                }
            }
        }
        return trendList;
    }

    public List<StaffTradeEveryDayVO> addDayData(List<StaffTradeEveryDayVO> list, Integer day) {
        //获取今天日期
        LocalDate today = LocalDate.now();
        //获取前几天日期
        LocalDate beforeDay = today.plusDays(-day);

        List<StaffTradeEveryDayVO> dailyStatistics = new ArrayList<>();
        for (LocalDate date = beforeDay; !date.isAfter(today); date = date.plusDays(1)) {
            StaffTradeEveryDayVO tradeEveryDay = new StaffTradeEveryDayVO();
            tradeEveryDay.setDayTime(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            tradeEveryDay.setQuantity(0);
            dailyStatistics.add(tradeEveryDay);
        }

        // 根据查询结果更新每日统计数据
        for (StaffTradeEveryDayVO dailyStatistic : dailyStatistics) {
            for (StaffTradeEveryDayVO staffTradeEveryDay : list) {
                if (dailyStatistic.getDayTime().equals(staffTradeEveryDay.getDayTime())) {
                    dailyStatistic.setQuantity(staffTradeEveryDay.getQuantity());
                }
            }
        }
        return dailyStatistics;
    }

    /**
     * @param month 月份
     * @Title getMonthFirstDay
     * @Desc 获取月份第一天
     * @Date 2024-06-04 14:48:30.712
     * @Return LocalDate
     */
    public LocalDate getMonthFirstDay(String month) {
        String time = month.substring(0, 7) + "-01";
        return LocalDate.parse(time, DateTimeFormatter.ofPattern(TimeUtils.YYYY_MM_DD));
    }

    /**
     * @Title getContainerIds
     * @Desc 获取员工的货柜ID
     * @Date 2024-06-04 14:49:05.574
     * @Return List<Long>
     */
    public List<Long> getContainerIdsByStaffId(Long staffId) {
        return simpleMapper.getContainerByStaffId(staffId);
    }

    /**
     * @param data        员工货柜数据
     * @param cabinetList 货柜信息
     * @Title getContainerCount
     * @Desc 获取货柜总数 激活数 未激活数
     * @Date 2024-06-04 14:49:20.370
     */
    public void countCabinet(StaffContainerVO data, List<CabinetCountDTO> cabinetList) {
        Integer totalCount = cabinetList.size();
        Integer useCount = 0;
        Integer unUseCount = 0;
        Integer normalVoltCount = 0;
        Integer lowVoltCount = 0;
        // 将激活与未激活分开
        for (CabinetCountDTO cabinet : cabinetList) {
            if (cabinet.getOnlineStatus().equals(OnlineStatus.ONLINE.getCode())) {
                useCount++;
            } else {
                unUseCount++;
            }
            if (cabinet.getBattleStatus().equals(0)) {
                normalVoltCount++;
            } else {
                lowVoltCount++;
            }
        }

        data.setTotalCount(totalCount);
        data.setOnlineCount(useCount);
        data.setOfflineCount(unUseCount);
        data.setNormalVoltCount(normalVoltCount);
        data.setLowVoltCount(lowVoltCount);
    }

    /**
     * @param original 原始值
     * @param later    比较值
     * @Title calculateGrowthRate
     * @Desc 计算两个数值百分比 前者被对比
     * @Date 2024-06-04 14:49:45.716
     * @Return String
     */
    public String calculateGrowthRate(BigDecimal original, BigDecimal later) {
        // 如果对比一样
        if (original.compareTo(later) == 0) {
            return "无变化";
        }
        BigDecimal fullRatio = BigDecimal.valueOf(100);
        int digitScale = 2;
        if (original.compareTo(later) < 0) {
            // 防止出现0的问题
            if (!DecimalUtils.compare(original)) {
                // 将大的减去小的再除以小的乘以百分比
                BigDecimal up = later.subtract(original).divide(original, digitScale, RoundingMode.CEILING).multiply(fullRatio);
                return "+" + up + "%";
            } else {
                return "+" + later.divide(BigDecimal.ONE, digitScale, RoundingMode.CEILING) + "%";
            }
        } else {
            if (!DecimalUtils.compare(later)) {
                BigDecimal down = original.subtract(later).divide(later, digitScale, RoundingMode.CEILING).multiply(fullRatio);
                return "-" + down + "%";
            } else {
                return "-" + original.divide(BigDecimal.ONE, digitScale, RoundingMode.CEILING) + "%";
            }
        }
    }

    public List<ScanStatisticsVO> scanStatisticsPage(ScanStatisticsParam param) {
        return simpleMapper.scanStatisticsPage(param);
    }

    public List<ScanStatisticsGroupVO> scanStatisticsGroup(ScanStatisticsParam param) {
        return simpleMapper.scanStatisticsGroup(param);
    }

    public List<FillCargoLocationVO> fillCargoLocation(FillCargoParam param) {
        LoginInfo user = SystemContext.getUser();
        Assert.isTrue(BeanUtils.isNotNull(user), ErrorEnum.BUSINESS_121006.getText());
        Long belongId = user.getBelongId();
        param.setBelongId(belongId);
        return complexMapper.fillCargoLocation(param);
    }
}